//  Copyright (c) 2008  Yoong-ki Ahn & Youngjin Kim < mexif@googlegroups.com>
//  See the enclosed file COPYING for license information (MIT Licence).
//  If you did not receive this file,
//  see http://www.opensource.org/licenses/mit-license.php.

#ifndef _MEXIF_JPEG_H_
#define _MEXIF_JPEG_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "mexiflib.h"


/// This simple jpeg scanner is intended to extract exif informations from jpeg.

typedef struct
{
	const unsigned char*	data;
	unsigned int			length;

	const unsigned char*	header_position;
	unsigned char			chunk_type;
	unsigned int			chunk_length;
	const unsigned char*	next_position;
	int						in_image;
} mexif_jpeg_t;

#pragma pack( push, 1 )
typedef struct
{
	unsigned char			Identifier[5];		// "JFIF\0"
	unsigned char			VersionMajor;
	unsigned char			VersionMinor;
	unsigned char			Units;
	mexif_uint16			Xdensity;
	mexif_uint16			Ydensity;
	unsigned char			Xthumbnail;
	unsigned char			Ythumbnail;
} mexif_jfif_partial_t;

typedef struct
{
    mexif_uint16            Length;
    unsigned char           PrecisionBit;
    mexif_uint16            Y;
    mexif_uint16            X;
    unsigned char           Nf;     // number of component. 1 for grayscale, 3 for color.
} mexif_frame_partial_t;
#pragma pack( pop )


/// ISO/IEC 10918-1 : 1993(E)
/// Table B.1 - Marker code assignments
enum mexif_jpeg_marker_t
{
	MEXIF_JPEG_MARKER_SOF0              = 0xc0,
	MEXIF_JPEG_MARKER_SOF1              = 0xc1,
	MEXIF_JPEG_MARKER_SOF2              = 0xc2,
	MEXIF_JPEG_MARKER_SOF3              = 0xc3,
	MEXIF_JPEG_MARKER_SOF5              = 0xc5,
	MEXIF_JPEG_MARKER_SOF6              = 0xc6,
	MEXIF_JPEG_MARKER_SOF7              = 0xc7,
	MEXIF_JPEG_MARKER_JPG               = 0xc8,
	MEXIF_JPEG_MARKER_SOF9              = 0xc9,
	MEXIF_JPEG_MARKER_SOF10             = 0xca,
	MEXIF_JPEG_MARKER_SOF11             = 0xcb,
	MEXIF_JPEG_MARKER_SOF13             = 0xcd,
	MEXIF_JPEG_MARKER_SOF14             = 0xce,
	MEXIF_JPEG_MARKER_SOF15             = 0xcf,
	MEXIF_JPEG_MARKER_DHT				= 0xc4,	// define huffman table(s)
	MEXIF_JPEG_MARKER_DAC				= 0xcc, // define arithmentic coding conditions

	MEXIF_JPEG_MARKER_RST0				= 0xd0,
	MEXIF_JPEG_MARKER_RST1				= 0xd1,
	MEXIF_JPEG_MARKER_RST2				= 0xd2,
	MEXIF_JPEG_MARKER_RST3				= 0xd3,
	MEXIF_JPEG_MARKER_RST4				= 0xd4,
	MEXIF_JPEG_MARKER_RST5				= 0xd5,
	MEXIF_JPEG_MARKER_RST6				= 0xd6,
	MEXIF_JPEG_MARKER_RST7				= 0xd7,

	MEXIF_JPEG_MARKER_StartOfImage		= 0xd8,
	MEXIF_JPEG_MARKER_EndOfImage        = 0xd9,
	MEXIF_JPEG_MARKER_StartOfScan       = 0xda,
	MEXIF_JPEG_MARKER_DQT				= 0xdb,
	MEXIF_JPEG_MARKER_DNL				= 0xdc,
	MEXIF_JPEG_MARKER_DRI				= 0xdd,
	MEXIF_JPEG_MARKER_DHP				= 0xde,
	MEXIF_JPEG_MARKER_EXP				= 0xdf,

	MEXIF_JPEG_MARKER_APP0				= 0xe0,
	MEXIF_JPEG_MARKER_APP1				= 0xe1,
	MEXIF_JPEG_MARKER_APP2				= 0xe2,
	MEXIF_JPEG_MARKER_JFIF				= 0xe0,
	MEXIF_JPEG_MARKER_EXIF				= 0xe1,
	MEXIF_JPEG_MARKER_APP15				= 0xef,

	MEXIF_JPEG_MARKER_Comment			= 0xfe,
	MEXIF_JPEG_MARKER_PseudoImage		= 0xff,
};

/// Do not process when mexif_jpeg_init failed
/// @return MEXIF_RET_OK for success.
mexif_return_t	MEXIF_API mexif_jpeg_init( mexif_jpeg_t* pjpeg, const void* data, unsigned int len );
void			MEXIF_API mexif_jpeg_close( mexif_jpeg_t* pjpeg );

/// When error occurs, check with 'invalid' function
void			MEXIF_API mexif_jpeg_next( mexif_jpeg_t* pjpeg );

/// is valid chunk?
/// TRUE if valid.
mexif_bool		MEXIF_API mexif_jpeg_isvalid( mexif_jpeg_t* pjpeg );

/// get chunk marker.
/// @return 0 or mexif_jpeg_marker_t type. 0 for invalid situation. 
/// check mexif_jpeg_isvalid for validness.
mexif_uint32	MEXIF_API mexif_jpeg_getmarker( mexif_jpeg_t* pjpeg );

mexif_pcstr		MEXIF_API mexif_jpeg_getmarkername( int marker );

/// get chunk length.
/// @return 0 for invalid situation. and 0 is also valid possible length.
/// check mexif_jpeg_isvalid for validness.
mexif_uint32	MEXIF_API mexif_jpeg_getlength( mexif_jpeg_t* pjpeg );

/// get chunk data.
/// start with length.
/// @return 0 or valid pointer. 0 for invalid sutation.
/// check mexif_jpeg_isvalid for validness.
const void*		MEXIF_API mexif_jpeg_getchunk( mexif_jpeg_t* pjpeg );

/// returns offset of header.
mexif_uint32	MEXIF_API mexif_jpeg_getoffset( mexif_jpeg_t* pjpeg );

/// is this chunk exif?
mexif_bool		MEXIF_API mexif_jpeg_is_exif( mexif_jpeg_t* pjpeg );

/// is this chunk jfif?
mexif_bool      MEXIF_API mexif_jpeg_is_jfif( mexif_jpeg_t* pjpeg );

mexif_return_t	MEXIF_API mexif_jpeg_get_jfif( mexif_jpeg_t* pjpeg, mexif_jfif_partial_t* pjfif );

/// parse jfif header
mexif_return_t	MEXIF_API mexif_jpeg_fill_jfif( mexif_jfif_partial_t* pjfif, const unsigned char* data, mexif_uint32 size );

/// get start of frame header
mexif_return_t  MEXIF_API mexif_jpeg_get_sof( mexif_jpeg_t* pjpeg, mexif_frame_partial_t * pframe );

#ifdef __cplusplus
}
#endif

#endif

